/**
 * Created on May 13, 2007
 */
package jvs.vfs.io;

import java.io.IOException;
import java.io.InputStream;
import java.util.Random;

/**
 * Unix /dev/random
 * 
 * @author qiangli
 * 
 */
public class RandomInputStream extends InputStream {
	private Random r = new Random();

	private byte[] buf = null;

	private int mark = -1;

	private int cnt = -1;

	/**
	 * 
	 */
	public RandomInputStream() {
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.io.InputStream#read()
	 */
	public int read() throws IOException {
		return nextByte();
	}

	private byte nextByte() {
		if (buf != null && mark < cnt) {
			return buf[mark++];
		}
		byte[] ba = new byte[1];
		r.nextBytes(ba);
		if (buf != null) {
			if (++cnt < buf.length) {
				buf[cnt] = ba[0];
				mark = cnt;
			} else {
				mark = -1;
				cnt = -1;
				buf = null;
			}
		}
		return ba[0];
	}
	
	public int available() throws IOException {
		return Integer.MAX_VALUE;
	}

	public void close() throws IOException {
	}

	public synchronized void mark(int readlimit) {
		buf = new byte[readlimit];
		mark = 0;
		cnt = 0;
	}

	public boolean markSupported() {
		return true;
	}

	public int read(byte[] b, int off, int len) throws IOException {
		if (b == null)
			throw new NullPointerException();
		if (off < 0 || len < 0 || off + len > b.length)
			throw new IndexOutOfBoundsException();
		if (len == 0)
			return 0;
		for (int i = off; i < off + len; i++) {
			b[i] = nextByte();
		}
		return len;
	}

	public int read(byte[] b) throws IOException {
		if (b == null)
			throw new NullPointerException();
		if (b.length == 0)
			return 0;
		for (int i = 0; i < b.length; i++) {
			b[i] = nextByte();
		}
		return b.length;
	}

	public synchronized void reset() throws IOException {
		if (buf == null) {
			throw new IOException("mark not called or readlimit exceeded");
		}
		mark = 0;
	}

	public long skip(long n) throws IOException {
		for (int i = 0; i < n; i++) {
			nextByte();
		}
		return n;
	}
}
